#include "Defs.h"
#include "Request.h"


Error_T::Code_T Request_T::Parse(const Buffer_T & rawStream)
{
	Header_T header;
	unsigned int ix = 0, iy;

	// 
	// Ignore first CRLF
	//

	if( rawStream.StartsWith("\r\n", false) )
	{
		ix += 2;
	}

	//
	// Find Verb
	//

	iy = rawStream.IndexOf(" ", ix);
	if( iy == rawStream.Length() )
	{
		return Error_T::ERR_REQUEST_FORMAT;
	}

	_verb = rawStream.SubBuffer(ix, iy - ix);
	ix = iy + 1;

	//
	// Validate we only have 1 SP
	//

	if( (rawStream.Length() <= ix) || (rawStream[ix] == ' ') )
	{
		return Error_T::ERR_REQUEST_FORMAT;
	}

	//
	// Find Uri
	//
	
	iy = rawStream.IndexOf(" ", ix);
	if( iy == rawStream.Length() )
	{
		return Error_T::ERR_REQUEST_FORMAT;
	}

	_uri = rawStream.SubBuffer(ix, iy - ix);
	ix = iy + 1;

	//
	// Validate we only have 1 SP
	//
	
	if( (rawStream.Length() <= ix) || (rawStream[ix] == ' ') )
	{
		return Error_T::ERR_REQUEST_FORMAT;
	}

	//
	// Find Version
	//
	
	iy = rawStream.IndexOf("\r\n", ix);
	if( iy == rawStream.Length() )
	{
		return Error_T::ERR_REQUEST_FORMAT;
	}

	_version = rawStream.SubBuffer(ix, iy - ix);
	ix = iy + 2;

	// 
	// Parse http request headers until
	// our current position is at the
	// end of the request headers.
	//
	
	while( ix != (rawStream.Length() - 2) )
	{
		// 
		// If we are still validating the header name then
		// we must try to find:
		// - ASCII_COLON (find the end of a header name)
		// - "\r\n" (find the end of a header)
		// If we find "\r\n" before ASCII_COLON (in header
		// name validation), then the request will be invalid,
		// since an Http Request Header must always contain an
		// ASCII_COLON.
		//
		// If we are validating the header value, then we only
		// need to find an "\r\n".
		//

		iy = rawStream.IndexOf(":", ix);
		if( iy == rawStream.Length() )
		{
			iy = rawStream.IndexOf("\r\n", ix);
			if( iy == rawStream.Length() )
			{
				return Error_T::ERR_REQUEST_FORMAT;
			}
		}

		if( rawStream[iy] == '\r' )
		{
			return Error_T::ERR_REQUEST_FORMAT;
		}

		// 
		// We reached this stage, so a header name was found
		//

		header.name = rawStream.SubBuffer(ix, iy - ix);
		ix = iy + 1;
		
		// 
		// Find the end of the header value
		//

		iy = rawStream.IndexOf("\r\n", ix);
		if( iy == rawStream.Length() )
		{
			return Error_T::ERR_REQUEST_FORMAT;
		}

		// 
		// We reached this stage, so header value was found.
		//
		
		header.value = rawStream.SubBuffer(ix, iy - ix);
		ix = iy + 2;

		//
		// Add the header name/value
		//

		_headerList.Add(new Header_T(header));
	}

	// 
	// Parse the Uri in:
	// - Schema
	// - Url
	// - Query
	// - Fragment
	//

	//
	// If the Uri starts with a schema
	//
	
	if( _uri.StartsWith("http://", false) )
	{
		//
		// Find the end of the schema
		//

		ix = _uri.IndexOf("/", 7);
		if( ix == _uri.Length() )
		{
			_schema = _uri.SubBuffer(7);
			return Error_T::ERR_NONE;
		}

		_schema = _uri.SubBuffer(7, ix - 7);
	}
	else
	{
		ix = 0;
	}

	//
	// If there is no query string or fragment
	//

	iy = _uri.IndexOf("?", ix);
	if( iy == _uri.Length() )
	{
		iy = _uri.IndexOf("#", ix);
		if( iy == _uri.Length() )
		{
			_url = _uri.SubBuffer(ix);
			return Error_T::ERR_NONE;
		}
	}

	_url = _uri.SubBuffer(ix, iy - ix);
	ix = iy;

	//
	// If a fragment was found
	//

	if( _uri[ix++] == '#' )
	{
		_fragment = _uri.SubBuffer(ix);
		return Error_T::ERR_NONE;
	}

	//
	// A Query was found. Check if there is a fragment
	//
	
	iy = _uri.IndexOf("#", ix);
	if( iy == _uri.Length() )
	{
		_query = _uri.SubBuffer(ix);
		return Error_T::ERR_NONE;
	}

	_query = _uri.SubBuffer(ix, iy - ix);
	_fragment = _uri.SubBuffer(iy + 1);

	return Error_T::ERR_NONE;
}
